home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000
/
Ham Radio 2000.iso
/
ham2000
/
tcp_ip
/
gracil
/
p10dvr
/
p10_at.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-07
|
21KB
|
867 lines
/****************************************************************************
*
* COPYRIGHT 1990,91,92 BY GRACILIS INC.
*
* 623 Palace St.
* Aurora, Il. 60506
*
* (708)-801-8800 Office
* (708)-844-0183 (FAX - Support BBS)
*
* GRACILIS, INC., MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS
* SOFTWARE FOR ANY PURPOSE.
*
* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
*
* Permission is granted for non-commercial use/distribution only, as long as
* this copyright header is included intact and unaltered.
*
******************************************************************************/
/************************************************************************
*
*
* File: ipc.c
*
* Rev : 1.0
*
* Description:
*
* This File contains routines that implement PackeTen Switch's
* inter-processor driver with an interface to KA9Q's TCP/IP suite.
*
*
* Routines:
*
* ipc_attach - Performs attach functions for TCP/IP, i.e.
* attach the ipc driver to TCP/IP.
*
* ipc_raw - Applications' routine for transmitting
* a message via ipc driver.
*
* ipc_recv - Applications' routine for receiving a message
* from the ipc driver.
*
* ipc_stat - Applications' routine for "displaying" the
* ipc driver statistics.
*
* ipc_ioctl - Set driver parameters.
*
* ipc_stop - Stop I/O
*
* ipc_init - Initialize the ipc hardware.
*
* ipc_txint - Handles transmit complete interrupts.
*
* ipc_rxint - Handles receive complete interrupts.
*
* ipc_entpt - Interrupt entry point
*
*/
/*
Note: As currently implemented, if the remote side of an IPC
link stops functioning, and we can not send our data to it,
eventually, all of NOS buffer memory will be used up.
Some strategy needs be developed to handle this problem...
It is analagous to a link which cannot transmit due to
a continuously appearing CARRIER on frequency.
*/
#include <stdio.h>
#include <dos.h>
#include "global.h"
#include "pc.h"
#include "config.h"
#include "mbuf.h"
#include "ax25.h"
#include "iface.h"
#include "lapb.h"
#include "proc.h"
#include "trace.h"
#include "netuser.h"
#include "proc.h"
#include "pktdrvr.h"
#include "commands.h"
#include "devparam.h"
#include "gracilis.h"
#include "p10.h"
#ifdef OLD_KA9Q
#else
#define tprintf printf
#endif
#ifdef PACKETEN_DEBUG
extern long recvcalls;
extern long rawcalls;
#endif
extern UNI_DCB P10_udcb[];
extern INTERRUPT (*P10oldvec) __ARGS((void)); /* Old vector contents */
extern int16 P10_vec; /* Vector number */
extern int16 P10Proc_id; /* The PC is processor 2!!! */
extern IPC *P10Ipc;
extern int16 P10Pcport;
extern INTERRUPT (*P10handler) __ARGS((void));
/********************************************************************
* IPC_ATTACH *
* *
* File: ipc.c *
* Rev : 1.0 *
* *
********************************************************************
*
*
* DESCRIPTION:
* -----------
* Attaches the PackeTen Switch's ipc driver to NOS.
*
* ARGUMENTS:
* ---------
* All argv's are strings
* argv[0]: hardware type, "ipc"
*
* argv[1]: vector, e.g., "2"
*
* argv[2]: "0" = PACKETEN main card
* "1" = PACKETEN daughter card
* "2" = IBM PC side of IPC
* argv[3]: interface "NAME"
*
* argv[4]: encap mode
*
* argv[5]: OPTIONAL - IPC memory base address
*
* argv[6]: OPTIONAL - PackeTen control Port address - Default 0x238
*
* argv[7]: OPTIONAL - Tx Queue Depth, num. of tx packets to allow in the
* "to be transmitted queue" at one time.
*
* argv[8]: OPTIONAL - # of rx buffers to preallocate !!! NOT IMPLEMENTED
*
* argv[9]: OPTIONAL - Ip address
*
* RETURN VALUES:
* -------------
* 0 - success
* -1 - failure, driver not attached and no memory left allocated
*
* GLOBAL INPUTS:
* -------------
*
* GLOBAL OUTPUTS:
* --------------
*
* FUNCTIONS CALLED:
* ----------------
* tprintf
* calloc
* malloc
* free
*
* IO:
* --
*
*
******************************************************************/
int
ipc_attach(argc,argv,p)
int argc;
char *argv[];
void *p; /* new for NOS */
{
extern struct iface *ifaces;
struct iface *intfc_p;
IPC_DCB *sp;
UNI_DCB *udcbp;
int devnum, an_ipc_is_attached;
int32 ipaddr; /* new for NOS */
char i_state; /* saved state of the interrupt level */
int i; /* gen purpose counter ... etc */
struct ipcbuf *rxarea;
long base_addr;
int16 port;
/*
* validate input params
*/
if ( argc < 5 )
{
tprintf("ipc_attach: too few arguments (%d) \r\n", argc);
tprintf("ipc <vector> <processor (dc|mc)> <name> <mode> [base addr] [ctl addr]\r\n");
tprintf(" [txQdepth] [rxbufs] [ip addr]\r\n");
return(-1);
}
#ifdef PACKETEN_DEBUG
tprintf("ipc_attach: argument count is %d\n",argc);
for(i=0;i<argc;i++)
tprintf("arg #%d: %s\n",i,argv[i]);
tprintf("\n\n");
#endif
/* set the udcb device # for this processor's ipc */
devnum = -1;
if(strcmpi(argv[2],"mc") == 0) devnum = 0;
if(strcmpi(argv[2],"dc") == 0) devnum = 1;
if(strcmpi(argv[2],"pc") == 0) devnum = 2;
if(devnum == -1)
{
tprintf("ipc_attach err: unknown processor id %s\r\n",argv[2]);
tprintf("Try 'mc' for PackeTen Main Card or 'dc' for Daughter Card.\n");
return(-1);
}
if((devnum) == P10Proc_id) /* Can't be same as Our local processor*/
{
tprintf("ipc_attach err: processor id %s is LOCAL!!!\r\n",argv[2]);
tprintf("Try 'mc' for PackeTen Main Card or 'dc' for Daughter Card.\n");
return(-1);
}
if ( if_lookup(argv[3]) != NULLIF ) /* new for NOS */
{
tprintf("Interface %s already exists \r\n", argv[3]);
return(-1);
}
/* new for NOS, Set the IP address */
ipaddr = Ip_addr; /* default value */
if ( argc >= 10 )
ipaddr = resolve(argv[9]);
if ( ipaddr == 0 )
{
tprintf(Noipaddr);
return(-1);
}
if(argc >= 6)
{
#ifdef PACKETEN_DEBUG
tprintf("Base address = %lx\n",(unsigned long)ghtol(argv[5]));
#endif
P10Ipc = (IPC *)ghtol(argv[5]);
base_addr = ptol(P10Ipc);
if( (base_addr != 0x80000000) &&
(base_addr != 0x90000000) &&
(base_addr != 0xA0000000) &&
(base_addr != 0xC0000000) &&
(base_addr != 0xD0000000) &&
(base_addr != 0xE0000000)
)
{
tprintf("Bad IPC base address specified: %lx\n",base_addr);
return(-1);
}
}
/* Did the user specify a port address? */
if(argc >= 7)
{
if((port = atoi(argv[6])) == 0)
{
tprintf("Illegal Control Port address specified: %s\n",argv[6]);
return(-1);
}
else P10Pcport = port;
}
/* Gracilis 7/25/92 DGL */
/* Be sure to enable the dual port RAM for release 2 CPU's */
ipc_mapin(P10Pcport);
udcbp = &P10_udcb[devnum]; /* dev num is index number!!! */
/* See if already attached */
if ( udcbp->attached )
{
tprintf("ipc_attach error: IPC channel already attached; interface is %s\n", argv[3]);
return(-1);
}
/*
* try to allocate necessary memory
*/
intfc_p = (struct iface *)calloc(1,sizeof(struct iface));
if ( intfc_p != (struct iface *)0 )
{
intfc_p->name = malloc((unsigned)strlen(argv[3])+2);
if (intfc_p->name != NULLCHAR )
{
intfc_p->hwaddr = NULL;
}
else
{
free(intfc_p);
tprintf("ipc_attach error: no memory for interface name, size 7 bytes, interface %s", argv[3]);
return(-1);
}
}
else
{
tprintf("ipc_attach error: no memory for interface struct, size of %d, interface %s", sizeof(struct iface),argv[3]);
return(-1);
}
/* allocate and clear the device control block */
sp = (IPC_DCB *)calloc(1,sizeof(IPC_DCB));
if ( sp == (IPC_DCB *)0 )
{
free(intfc_p->name);
free(intfc_p);
tprintf("ipc_attach error: no memory for device control block structure, size of %d, interface %s", sizeof(IPC_DCB),argv[3]);
return(-1);
}
/* this needs to be done BEFORE the buffers are allocated... */
/* DGL 4/17/90 */
/* 7/25/92 DGL */
/* intfc_p->type = CL_AX25; */
/* attempt to set the encapsulation type */
/* This needs to be done before we preallocate */
/* receive buffers, since we have to indicate the */
/* encap type in the buffers for later use. */
/* Only allow type "IPC" or "AX25" */
if(((strcmpi(argv[4],"ax25") != 0) &&
(strcmpi(argv[4],"ipc") != 0)) ||
(setencap(intfc_p,argv[4]) != 0))
{
/* An invalid encap mode was specified... */
/* Just print a message and exit */
tprintf("Illegal mode specification: %s\n",argv[4]);
free(intfc_p->name);
free(intfc_p);
free(sp);
return(-1);
}
/* preallocate rx buffers */
/* set the rxavailbufs parameter */
if ( argc >= 9 )
sp->rxavailbufs = atoi(argv[8]);
else
sp->rxavailbufs = IPC_BUF_CNT + 1;
/* get the requested rx pre-allocated mbuf's */
sp->rxavailq = NULLBUF;
f_getavail(&(sp->rxavailq), (sp->rxavailbufs), IPC_BUF_SIZE, &(sp->rxavailcount), intfc_p, (bool)FALSE);
#ifdef PACKETEN_DEBUG
tprintf("ipc_attach: rxavailbufs is %d, rxavailcount is %d\n", sp->rxavailbufs, sp->rxavailcount);
#endif
if(sp->rxavailcount < sp->rxavailbufs)
{
tprintf("ipc_attach: Insufficient Memory to preallocate rx buffers...\n");
free(intfc_p->name);
free(intfc_p);
/* Now free all successfully allocated buffers... */
while((sp->rxbufp = f_dequeavail(&sp->rxavailq,&sp->rxavailcount)) != NULLBUF)
free(sp->rxbufp);
free(sp);
return(-1);
}
/* setup the receive buffer pointer */
sp->rxbufp = f_dequeavail(&sp->rxavailq,&sp->rxavailcount);
/*
* Setup the interface structure and link it to the list
* of interface structures.
*/
/* the Ascii name of the driver unit */
strcpy(intfc_p->name,argv[3]);
/* fill in this "Unit's" driver control block */
intfc_p->mtu = (IPC_BUF_SIZE - MAX_AX25_HDR_LEN);
intfc_p->ioctl = ipc_ioctl;
intfc_p->raw = ipc_raw;
intfc_p->stop = ipc_stop;
intfc_p->dev = devnum;
intfc_p->addr = ipaddr;
/* new for NOS Mycall replaces (char *)&mycall */
intfc_p->hwaddr = mallocw(AXALEN);
memcpy(intfc_p->hwaddr,Mycall,AXALEN);
/* lastly, but very importantly, put in the LL of interfaces */
intfc_p->next = Ifaces;
Ifaces = intfc_p;
/*
* Initialize the unit's driver control block
*/
sp->iface = intfc_p; /* new for NOS - save the iface */
/* address for use in queueing */
/* mbufs onto Hopper */
sp->destproc = (devnum);
sp->xmtq = (struct drvbuf *)0;
sp->xmtqtail = (struct drvbuf *)0;
sp->freem = (struct drvbuf *)0;
if ( argc >= 8 )
sp->txq_depth = atoi(argv[7]);
else
sp->txq_depth = IPC_TX_DEPTH_DEFAULT;
/* no need to init stats because calloc zero-ed the sp */
sp->intcnt = 0;
sp->txcnt = 0;
/*
* Now for the hardware dependent initializations.
*
* intfc_p->dev tells which unit/dev
*
*/
#ifdef PACKETEN_DEBUG
tprintf("ipc_attach: intfc_p->dev = %x config IPC HW \r\n", intfc_p->dev);
#endif
/* HERE WE start DIDDLING the actual hardware regs... */
/* So to be safe, NO ints... */
i_state = dirps();
/* reset all possible pending ints for IPC */
clrint302dc();
clrint302mc();
switch(P10Proc_id)
{
case 0: switch(sp->destproc)
{
case 1: sp->rxarea = (struct ipcbuf *)P10Ipc->proc[0].proc_buf[0];
sp->rxcontrol = (uchar *)&P10Ipc->proc[0].control[0];
sp->txcontrol = (uchar *)&P10Ipc->proc[1].control[0];
sp->txarea = (struct ipcbuf *)P10Ipc->proc[1].proc_buf[0];
break;
case 2: sp->rxarea = (struct ipcbuf *)P10Ipc->proc[0].proc_buf[1];
sp->rxcontrol = (uchar *)&P10Ipc->proc[0].control[1];
sp->txcontrol = (uchar *)&P10Ipc->proc[2].control[0];
sp->txarea = (struct ipcbuf *)P10Ipc->proc[2].proc_buf[0];
break;
default: break;
}
break;
case 1: switch(sp->destproc)
{
case 0: sp->rxarea = (struct ipcbuf *)P10Ipc->proc[1].proc_buf[0];
sp->rxcontrol = (uchar *)&P10Ipc->proc[1].control[0];
sp->txcontrol = (uchar *)&P10Ipc->proc[0].control[0];
sp->txarea = (struct ipcbuf *)P10Ipc->proc[0].proc_buf[0];
break;
case 2: sp->rxarea = (struct ipcbuf *)P10Ipc->proc[1].proc_buf[1];
sp->rxcontrol = (uchar *)&P10Ipc->proc[1].control[1];
sp->txcontrol = (uchar *)&P10Ipc->proc[2].control[1];
sp->txarea = (struct ipcbuf *)P10Ipc->proc[2].proc_buf[1];
break;
default: break;
}
break;
case 2: switch(sp->destproc)
{
case 0: sp->rxarea = (struct ipcbuf *)P10Ipc->proc[2].proc_buf[0];
sp->rxcontrol = (uchar *)&P10Ipc->proc[2].control[0];
sp->txcontrol = (uchar *)&P10Ipc->proc[0].control[1];
sp->txarea = (struct ipcbuf *)P10Ipc->proc[0].proc_buf[1];
break;
case 1: sp->rxarea = (struct ipcbuf *)P10Ipc->proc[2].proc_buf[1];
sp->rxcontrol = (uchar *)&P10Ipc->proc[2].control[1];
sp->txcontrol = (uchar *)&P10Ipc->proc[1].control[1];
sp->txarea = (struct ipcbuf *)P10Ipc->proc[1].proc_buf[1];
break;
default: break;
}
break;
default : tprintf("Invalid processor ID!!!\n");
break;
}
/* Initialize IPC RX buffer descriptors */
rxarea = sp->rxarea;
#ifdef PACKETEN_DEBUG
restore(i_state);
tprintf("rxarea's at:\n");
#endif
for(i=0;i<IPC_BUF_CNT;i++)
{
#ifdef PACKETEN_DEBUG
tprintf("%d at %lx; ",i, &rxarea[i]);
#endif
/* mark the buffers inactive */
rxarea[i].active = (unsigned char)FALSE;
rxarea[i].msbcnt = (unsigned char)0;
rxarea[i].lsbcnt = (unsigned char)0;
}
#ifdef PACKETEN_DEBUG
tprintf("\n");
fflush(stdout);
i_state = dirps();
#endif
an_ipc_is_attached = FALSE;
/* 0,1,2 are IPC chan/dev */
for (i=0; i<P10_MAXIPC; i++)
if (P10_udcb[i].type == IPC_LINK) an_ipc_is_attached = TRUE;
/* only set the vector if no IPC link is attached */
if ( an_ipc_is_attached == FALSE )
{
/* tell other processors this processor is talking */
P10Ipc->active[P10Proc_id] = TRUE;
/* Save old vector and write new vector */
P10_vec = htoi(argv[1]);
P10oldvec = getirq(P10_vec);
/* Write ipc's interrupt vector */
if (setirq(P10_vec, P10handler) == -1)
{
tprintf("ipc_attach err:IRQ %u out of range\n",P10_vec);
free(intfc_p->name);
free(intfc_p);
/* Now free all successfully allocated buffers... */
while ( (sp->rxbufp = f_dequeavail(&sp->rxavailq,&sp->rxavailcount)) != NULLBUF)
free(sp->rxbufp);
free(sp);
restore(i_state);
return(-1);
}
}
/* send control msg to other end, tell him I reset my ipc link */
#ifdef PACKETEN_DEBUG
restore(i_state);
tprintf("sp->txcontrol = %lx\n",sp->txcontrol);
fflush(stdout);
i_state = dirps();
#endif
*sp->txcontrol = IPC_RESET;
sp->txindex = sp->rxindex = 0;
*sp->rxcontrol = 0;
/* force an interrupt to destination processor, to make him see */
/* my control message */
/* If the destination is the "Main Card"... */
if(sp->destproc == 0)
int302mc();
else /* otherwise interrupt daughter 302 card */
int302dc();
/*
* Universal Driver Control Block and
* Vector related initializations
*/
udcbp->attached = TRUE;
udcbp->type = IPC_LINK;
/* set address of the unit's driver control block */
udcbp->dcbp = (char *)sp;
/* enable general ints */
restore(i_state);
/* new for NOS - start the two processes needed by the */
/* sync driver; one is for getting pre-allocated buffers */
/* the other is for kicking the transmitter after its */
/* timer has expired or when it needs a transmitted */
/* message free-ed. P.S. must do after attached set to TRUE */
#ifdef PACKETEN_DEBUG
tprintf("ipc_attach: calling newproc for ipc_rxavget \n");
#endif
sp->rxavproc = newproc("ipc rxavget",150,ipc_rxavget,devnum,NULL,NULL,0);
#ifdef PACKETEN_DEBUG
tprintf("ipc_attach: calling newproc for ipc_freetx \n");
#endif
sp->freetxproc = newproc("ipc freetx",150,ipc_freetx,devnum,NULL,NULL,0);
/* DONE */
#ifdef PACKETEN_DEBUG
tprintf("ipc_attach: All done!!! \n");
#endif
if ( an_ipc_is_attached == FALSE )
maskon(P10_vec);
return(0);
}
/*
* End of ipc_attach()
******************************************************************/
/*
* Display a PackeTen Switch Inter-Processor Communications channel's
* statistics.
*/
int
doipcstat(argc,argv,p)
int argc;
char *argv[];
void *p; /* new for NOS */
{
IPC_DCB *dcbp;
UNI_DCB *udcbp;
int16 dev;
/* Header for the IPC channel's on the card */
tprintf("\n PackeTen Switch Inter-Processor Comm Channel Statistics\n\n");
tprintf("Name/To RxPacks RxNoBufs TxPacks TxFlush IntCnt TxqDepth RxAvail\n");
tprintf("------- --------- -------- --------- -------- --------- -------- -------\n");
for (dev=0, udcbp = &P10_udcb[0]; dev < P10_MAXIPC; udcbp++, dev++)
{
if ( udcbp->type == IPC_LINK )
{
dcbp = (IPC_DCB *)udcbp->dcbp;
/* tprintf("%4s/%2s %9.9d %8.8ld %9.9ld %8.8ld %9.9ld %8.8ld %7.7ld\n",
*/
tprintf("%4s/%2s %#9lu %#8u %#9lu %#8u %#9lu %#8u %#7u\n",
dcbp->iface->name,
((dev == 5)?"MC": (dev == 6)?"DC" : "PC"),
dcbp->rxpackcnt,
dcbp->nobufs,
dcbp->txpackcnt,
dcbp->txflush,
dcbp->intcnt,
dcbp->txq_depth,
dcbp->rxavailcount);
}
} /* end of for loop */
tprintf("\n");
return(0);
}
/* Subroutine to set kiss params in channel tables */
int32
ipc_ioctl(iface,cmd,set,val)
struct iface *iface;
int cmd;
int set;
int32 val;
{
IPC_DCB *dcbp;
dcbp = (IPC_DCB *)P10_udcb[iface->dev].dcbp;
switch(cmd){
case PARAM_RXBUFS:
if(set)
{
dcbp->rxavailbufs = (int16)val;
/* signal the process which */
/* allocates the rx buffers */
psignal(&ipc_bufpp[dcbp->destproc],1);
}
return dcbp->rxavailbufs;
case PARAM_TXQMAX:
if(set)
dcbp->txq_depth = (int16)val;
return dcbp->txq_depth;
}
return -1;
}
/*
* Stop I/O
*/
int
ipc_stop(intfcp)
struct iface *intfcp;
{
IPC_DCB *sp;
int16 dev;
UNI_DCB *udcbp;
int16 i_state, i, an_ipc_is_attached;
struct drvbuf *xbufp, *tmpptr;
struct mbuf *tmpmbufp;
dev = intfcp->dev;
udcbp = &P10_udcb[dev]; /* dev num is index number!!! */
if ( udcbp->attached != TRUE )
{
tprintf("ipc_stop err: Device already stopped/de-attached!!\n");
return(0);
}
sp = (IPC_DCB *)P10_udcb[dev].dcbp;
/* Turn off interrupts */
i_state = dirps();
/* mark ipc as available - do it now for if below */
udcbp->attached = FALSE;
udcbp->type = 0;
udcbp->dcbp = NULL;
an_ipc_is_attached = FALSE;
for (i=0; i<P10_MAXIPC; i++)
if (P10_udcb[i].type == IPC_LINK)
an_ipc_is_attached = TRUE;
/* when both IPC interfaces are stopped - tell other */
/* processors' this processor ain't talking */
if ( an_ipc_is_attached == FALSE )
{
/* tell the other processors this processor's IPC */
/* is closed */
P10Ipc->active[P10Proc_id] = FALSE;
/* Turn off interrupts */
maskoff(P10_vec);
/* Restore interrupt vector used by IPC handler */
setirq(P10_vec, P10oldvec);
}
restore(i_state);
/* kill off the support processes */
/* so they don't allocate memory */
/* whils't we're freeing it */
killproc(sp->rxavproc);
killproc(sp->freetxproc);
/*
* Flush all buffers and queue's
*/
/* free preallocated rx buffers on the rx available queue */
while((tmpmbufp = f_dequeavail(&sp->rxavailq,&sp->rxavailcount)) != NULLBUF)
free(tmpmbufp);
/* free up any pending transmit buffers... */
while(sp->xmtq != (struct drvbuf *)0 )
{
tmpptr = sp->xmtq->next;
free(sp->xmtq);
sp->xmtq = tmpptr;
}
/* Free any previously sent frames, which are in the waiting to be */
/* free'd queue */
/* disable ints here to get queue head... */
i_state = dirps(); /* seems unecessary */
xbufp = sp->freem;
sp->freem = (struct drvbuf *)0;
restore(i_state);
/* Here xbufp is a "to be free'd" */
/* queue pointer" */
/* now free memory of all the xmitted messages */
while ( xbufp != (struct drvbuf *)0 )
{
tmpptr = xbufp->next;
free((char *)xbufp);
xbufp = tmpptr;
}
/*
* Deallocate other driver related memory structures
*/
if ( sp->rxbufp != NULLBUF )
free(sp->rxbufp);
free(sp);
return(0);
}
/* Convert hex-ascii to integer */
static long int
ghtol(s)
char *s;
{
long int i = 0;
char c;
while((c = *s++) != '\0'){
if(c == 'x')
continue; /* allow 0x notation */
if(c == ':')
continue; /* allow : for seg:offset notation */
if('0' <= c && c <= '9')
i = (i * 16) + (c - '0');
else if('a' <= c && c <= 'f')
i = (i * 16) + (c - 'a' + 10);
else if('A' <= c && c <= 'F')
i = (i * 16) + (c - 'A' + 10);
else
break;
}
return i;
}